﻿using System;
using System.Collections.Generic;
using System.Linq;
using Mnk.Merger.Code.Repository;

namespace Mnk.Merger.Code.Commands
{
    class MergeSpy : IMergeSpy
    {
        private readonly IRepositoryFacade facade;

        public MergeSpy(IRepositoryFacade facade)
        {
            this.facade = facade;
        }

        public IEnumerable<MergeInfo> GetChanges(string sourceUrl, string targetUrl, string revisionFrom)
        {
            var sourceData = facade.GetChangedFiles(sourceUrl, revisionFrom);
            var targetData = facade.GetChangedFiles(targetUrl, revisionFrom, false);
            var source = Collect(sourceData);
            var target = Collect(targetData);
            var sourceFiles = source
                .Where(x=>!string.IsNullOrEmpty(x.Path))
                .GroupBy(x => x.Path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).First())
                .OrderBy(x=>x.Key);
            yield return new MergeInfo
            {
                Commits = sourceData.Keys.Count,
                Revisions = sourceData.Keys.ToArray()
            };
            foreach (var project in sourceFiles)
            {
                var changed = project.Distinct().ToArray();
                yield return new MergeInfo
                {
                    ProjectName = project.Key,
                    Commits = project.GroupBy(x=>x.Id).Count(),
                    ChangedFiles = changed.Count(),
                    BreakingChanges = ExtendedIntersect(project.ToArray(),target)
                };
            }
        }

        private static MergeSpyInfo[] Collect(IDictionary<string, List<string>> sourceData)
        {
            return sourceData.SelectMany(x => x.Value.Select(y => new MergeSpyInfo(x.Key, y))).ToArray();
        }

        private static IList<MergeSpyInfo> ExtendedIntersect(IList<MergeSpyInfo> left, IList<MergeSpyInfo> right)
        {
            var rightSet = new HashSet<string>(right.Select(x => x.Path));
            return left.Where(x => rightSet.Contains(x.Path))
                 .ToList();
        }
    }
}